import { useMasterStore } from "./master";
import type { Config } from "./master/types";
import { useAsyncRef } from "@/utils/use";
import { compare, deepClone } from "fast-json-patch";
import { defineStore } from "pinia";
import { computed, ref } from "vue";

export const useConfigStore = defineStore("config", () => {
  const masterStore = useMasterStore();

  const cache = {
    configLock: useAsyncRef({ supplier: masterStore.getConfigLock }),
    config: useAsyncRef({
      supplier: masterStore.getConfig,
      onSuccess: (value) => (config.value = deepClone(value)),
    }),
  };
  const config = ref<Config>();

  const cacheView = computed(() => ({
    configLock: cache.configLock.view(),
    config: cache.config.view(),
  }));
  const invertiblePatch = computed(() => {
    const configCache = cacheView.value.config;
    if (configCache.value !== undefined && config.value !== undefined) {
      return compare(configCache.value, config.value!, true);
    }
  });
  const patch = computed(() => {
    return invertiblePatch.value?.filter(({ op }) => op !== "test");
  });

  async function putConfigLock() {
    await cache.configLock.execute({
      supplier: async () => {
        const timestamp = await masterStore.putConfigLock();
        return { value: masterStore.configLock, timestamp };
      },
      onError: () => {
        if (cache.config.value.value !== undefined) {
          cache.config.state.value = "ready";
          cache.config.error.value = undefined;
        }
      },
      throwError: true,
    });
  }

  async function patchConfig() {
    await cache.config.execute({
      supplier: async () => {
        await masterStore.patchConfig(invertiblePatch.value!);
        return deepClone(config.value);
      },
      onSuccess: () => {},
      onError: () => {
        if (cache.config.value.value !== undefined) {
          cache.config.state.value = "ready";
          cache.config.error.value = undefined;
        }
      },
      throwError: true,
    });
  }

  function $reset() {
    cache.config.reset();
    cache.configLock.reset();
    config.value = undefined;
  }

  return {
    cache: cacheView,
    config,
    patch,
    fetchConfigLock: cache.configLock.execute,
    putConfigLock,
    fetchConfig: cache.config.execute,
    patchConfig,
    $reset,
  };
});
